import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Created by IntelliJ IDEA.
* User: torstein
* Date: 3/14/12
* Time: 11:36 AM
* To change this template use File | Settings | File Templates.
*/

public class Relation {

    private static final String SPLIT_CHARS_PATTERN = "[\\+\\-\\*\\^]";
    private static final String DECIMAL_PATTERN =  "\\d+(\\.\\d+)?";
    
    private String expression;
    private Quiver quiver;
    private Set<Named> elements = new HashSet<Named>();

    public Relation(Quiver quiver, String expression) {
        this.quiver = quiver;
        this.expression = expression;
        extractNamedObjects();
    }

    public Quiver getQuiver() {
        return quiver;
    }
    
    public boolean contains(Named object) {
        return elements.contains(object);
    }
    
    public Set getElements () {
        return elements;
    }
    
    public String toString () {        
        return expression;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (obj == this) {
            return true;
        }
        if (obj instanceof Relation) {
            Relation rel = (Relation) obj;
            return expression.equals(rel.expression);
        }
        return false;
    }

    private void extractNamedObjects() {
        String[] parts = expression.split(SPLIT_CHARS_PATTERN);
        int index = 0;
        for (String part : parts) {

            /* if it's not a decimal number, it must be a node or an arrow */
            if (!part.matches(DECIMAL_PATTERN)) {
                Named object = quiver.getArrow(part);
                if (object != null) {
                    elements.add(object);
                } else {
                    object = quiver.getNode(part);
                    if (object != null) {
                        elements.add(object);
                    }
                }
            }
        }
    }
    
    public static boolean validate(Quiver quiver, String relationString) {
        if (!relationString.isEmpty() && relationString.substring(relationString.length() - 1,
                relationString.length()).matches(SPLIT_CHARS_PATTERN)) {
            return false;
        }
        String[] parts = relationString.split(SPLIT_CHARS_PATTERN);
        int index = 0;
        for (String part : parts) {
            if (part.isEmpty()) {
                return false;
            }
            boolean number = part.matches(DECIMAL_PATTERN);

            if (index > 0 && relationString.charAt(index -1) == '^' && !number) {
                return false;
            }

            /* if it's not a decimal number, it must be a node or an arrow */
            if (!number && quiver.getArrow(part) == null && quiver.getNode(part) == null) {
                return false;
            }
            index += part.length() + 1; // + 1 to compensate for the operator sign
        }
        return true;
    }
}

